package de.koller.aframe.util.math;

import de.koller.aframe.util.misc.ColorGradient;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class Function3DPreview {
	public static boolean PRINT_PROGRESS = false;
	public static int STEP_INTERVAL = 100;
	public static int Z_STEPS = 20;
	public static int IMG_WIDTH = 200, IMG_HEIGHT = 200;
	public static int PANEL_WIDTH = 600, PANEL_HEIGHT = 600;
	public static int[] COLORS = new int[] {  
		0xff_0000ff, 
		0xff_00ffff, 
		0xff_00ff00,
		0xff_ffff00, 
		0xff_ff0000
	};
	
	private Function3DPreview() {}
	
	public static void showFunction( float x, float y, float z, float w, float h, float d,
			float minValue, float maxValue, IFunction3D function ) {
		
		FunctionPanel p = new Function3DPreview.FunctionPanel( function, x, y, z, w, h, d, minValue, maxValue );
		JOptionPane.showMessageDialog( 
				null, 
				p,
				"Funktionsvorschau", 
				JOptionPane.PLAIN_MESSAGE );
		
		p.dthread.running = false;
	}
	
	private static class DepthThread extends Thread {

		private boolean running = true;
		private final FunctionPanel panel;

		public DepthThread( FunctionPanel panel ) {
			this.panel = panel;
		}
		
		@Override
		public void run() {
			while( running ) {
				panel.currentIndex++;
				panel.currentIndex %= Z_STEPS;
				try {
					Thread.sleep( STEP_INTERVAL );
				} catch( InterruptedException ex ) {}
				panel.repaint();
			}
		}
		
	}
	
	private static class FunctionPanel extends JPanel {

		private final float maxValue;
		private final float minValue;
		private final float vx, vy, vz, vw, vh, vd;
		private final BufferedImage[] img = new BufferedImage[ Z_STEPS ];
		private final IFunction3D function;
		
		private int currentIndex = 0;
		private DepthThread dthread = new DepthThread( this );
		
		private FunctionPanel( IFunction3D function, float x, float y, float z, float w, float h, float d,
				float minValue, float maxValue ) {
			super();
			this.setPreferredSize( new Dimension( PANEL_WIDTH, PANEL_HEIGHT ) );
			this.setBackground( Color.WHITE );
			
			this.function = function;
			
			this.vx = x;
			this.vy = y;
			this.vz = z;
			this.vw = w;
			this.vh = h;
			this.vd = d;
			
			this.minValue = minValue;
			this.maxValue = maxValue;
			
			for( int i = 0; i < img.length; i++ )
				img[i] = new BufferedImage( IMG_WIDTH, IMG_HEIGHT, BufferedImage.TYPE_INT_RGB );
			fillImg();
			dthread.start();
		}
		
		private void fillImg() {
			for( int z = 0; z < Z_STEPS; z++ ) {
				for( int x = 0; x < IMG_WIDTH; x++ )
					for( int y = 0; y < IMG_HEIGHT; y++ ) {
						float fx = vw / IMG_WIDTH * x + vx;
						float fy = vh / IMG_HEIGHT * y + vy;
						float fz = vd / Z_STEPS * z + vz;
						
						img[z].setRGB( x, y, getColor( function.getValue( fx, fy, fz ) ) );
					}
				if( PRINT_PROGRESS )
					System.out.println( z + " / " + Z_STEPS );
			}
		}
		
		private int getColor( float f ) {
			float k = (f - minValue) * (1f / (maxValue - minValue));
			return ColorGradient.cubic( k, COLORS );
		}
		
		@Override
		protected void paintComponent( Graphics g ) {
			super.paintComponent( g );
			
			Graphics2D g2 = (Graphics2D)g;
			g2.drawImage( img[currentIndex], 0, 0, PANEL_WIDTH, PANEL_HEIGHT, null );
		}
		
	}
	
}
